!pip install matplotlib
!pip install keras-tuner
!pip install seaborn
from stanford_dogs_utils import *
import numpy as np
import pandas as pd
import seaborn as sns
import os
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import tensorflow as tf
import cv2 as cv
from tensorflow.keras.preprocessing import image
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import timeit
import os
import pickle
from sklearn.metrics import classification_report, confusion_matrix
import keras_tuner as kt
from tensorflow.keras.models import load_model
gpu_info = !nvidia-smi
gpu_info = '\n'.join(gpu_info)
if gpu_info.find('failed') >= 0:
print('Not connected to a GPU')
else:
print(gpu_info)
annotations_dir = './annotation/Annotation/'
images_dir = './images/Images'
# Define path to data
#annotations_dir = './Dogs/Annotation'
#images_dir = './Dogs/Images'
# Count the number of classes (dogs breeds)
breed_list = os.listdir(images_dir)
print("Number of breeds in dataset:", (len(breed_list)))
# Count number of pictures for each breed
df_breeds = pd.DataFrame(
index=[breed.split('-',1)[1]
for breed in breed_list],
data=[len(os.listdir(images_dir + "/" + name))
for name in breed_list],
columns=["num_pictures"])
# Plot results
fig, ax = plt.subplots(1, 1, figsize=(15,8))
df_breeds.plot(kind="bar",
legend=False,
ax=ax)
ax.axhline(df_breeds["num_pictures"].mean(),
color='r', alpha=.7,
linestyle='--',
label="Mean of pictures")
plt.title("Number of pictures for each "\
"dogs breeds of Dataset",
color="#343434", fontsize=22)
plt.legend()
plt.show()
for i in np.random.randint(0, len(breed_list), size=3):
show_images_classes(images_dir, breed_list[i], 5)
One good practice over here is to start resizing our pictures as it will make the job of NN models easier
Image Preprocessing
1.1. Quick overview of data
1.2. Pictures resizing
1.3. Chaging histograms of pictures
1.4. Applying filters
1.5. Data augmentation
CNN from scratch
2.1. Preparing data
2.2. Construction du modèle CNN
2.3. Training and Evaluating CNN
Using pretrained models: VGG-16, Xception, Resnet50
3.1. VGG-16
3.2. Xception
3.3. Resnet50
3.4. Comparing results
# Define test image
img_test = (images_dir
+ "/"
+ "n02096585-Boston_bull/n02096585_2809.jpg")
img_test = cv.imread(img_test)
# setting dim of the resize
height = 299
width = 299
dim = (width, height)
# resize image with OpenCV
res_img = cv.resize(img_test, dim, interpolation=cv.INTER_LINEAR)
# Show both img
fig = plt.figure(figsize=(16,6))
plt.subplot(1, 2, 1)
plt.imshow(img_test)
plt.title("Original shape : {}".format(img_test.shape))
plt.subplot(1, 2, 2)
plt.imshow(res_img)
plt.title("Resized shape : {}".format(res_img.shape))
plt.suptitle("Resizing image",
color="black",
fontsize=22, y=.98)
plt.show()
# Transform image with differents color sets
img_RGB = cv.cvtColor(img_test, cv.COLOR_BGR2RGB)
img_grayscale = cv.cvtColor(img_test, cv.COLOR_RGB2GRAY)
img_YUV = cv.cvtColor(img_test,cv.COLOR_BGR2YUV)
plot_histogram(["RGB", img_RGB], ["YUV", img_YUV])
We can see from the chart on the right that the light is accumulated on the center of the picture, hence we need to compensate for that.
# Equalization
img_YUV[:,:,0] = cv.equalizeHist(img_YUV[:,:,0])
img_equ = cv.cvtColor(img_YUV, cv.COLOR_YUV2RGB)
plot_histogram(["RGB", img_RGB], ["Equalized", img_equ])
# Apply non-local means filter on test img
dst_img = cv.fastNlMeansDenoisingColored(
src=img_equ,
dst=None,
h=10,
hColor=10,
templateWindowSize=7,
searchWindowSize=21)
# Show both img
fig = plt.figure(figsize=(16,6))
plt.subplot(1, 2, 1)
plt.imshow(img_equ)
plt.title("Original Image")
plt.subplot(1, 2, 2)
plt.imshow(dst_img)
plt.title("Filtered Image")
plt.suptitle("Non-local Means Filter",
color="black",
fontsize=22, y=.98)
plt.show()
#Initilize Data Generator Keras
augmented_datagen = ImageDataGenerator(
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')
# Convert test img to array
x = image.img_to_array(img_test)
x = x.reshape((1,) + x.shape)
i=0
fig = plt.figure(figsize=(16,12))
for batch in augmented_datagen.flow(x, batch_size=1):
ax = fig.add_subplot(3,4,i+1)
ax.imshow(image.array_to_img(batch[0]))
i += 1
if i % 12 == 0:
break
plt.suptitle("Data Augmentation with Keras",
color="black",
fontsize=22, y=.90)
plt.show()
custom_breed_list = [
'n02096294-Australian_terrier',
'n02093256-Staffordshire_bullterrier',
'n02105505-komondor',
'n02107142-Doberman',
'n02086240-Shih-Tzu',
'n02111500-Great_Pyrenees',
'n02108915-French_bulldog',
'n02100735-English_setter',
'n02102318-cocker_spaniel',
'n02108915-French_bulldog',
'n02111129-Leonberg',
'n02106662-German_shepherd',
'n02110185-Siberian_husky',
'n02101006-Gordon_setter',
'n02109961-Eskimo_dog',
'n02088094-Afghan_hound',
'n02106166-Border_collie',
'n02106550-Rottweiler',
'n02108422-bull_mastiff',
'n02107574-Greater_Swiss_Mountain_dog',
]
#20 dog races selected in this project
# Define numbers of breeds to preprocess
num_breeds = len(custom_breed_list)
# Execute preprocessor on selection
start_time = timeit.default_timer()
# X = images
# y = labels
X, y = preprocessing_cnn(custom_breed_list, 299, 299)
# Convert in numpy array
X = np.array(X)
y = np.array(y)
preprocess_time = timeit.default_timer() - start_time
print("-" * 50)
print("Execution time for preprocessing :")
print("-" * 50)
print("Number of images preprocessed : {}"\
.format(len(y)))
print("Shape of images np.array : {}"\
.format(X.shape))
print("Total time : {:.2f}s".format(preprocess_time))
# Show exemple preprocessed image
plt.imshow(image.array_to_img(X[10]));
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
# The goal of the code below is to change the order of the data to avoid any abnormal patterns
# Using np.shuffle
img_space = np.arange(X.shape[0])
np.random.seed(8)
# Shuffle the space
np.random.shuffle(img_space)
# Apply to X and y in same order
X = X[img_space]
y = y[img_space]
# Change X type
X = X.astype(np.float32)
# Encode y text data in numeric
encoder = LabelEncoder()
encoder.fit(y)
y = encoder.transform(y)
with open("./encoder.pickle", "wb") as f:
pickle.dump(encoder, f)
# Checking encoder created classes
print(encoder.classes_)
### Create train and test set
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 42)
print("-" * 50)
print("Size of created sets :")
print("-" * 50)
print("Train set size = ",x_train.shape[0])
print("Test set size = ",x_test.shape[0])
This is the last step of of the data prep. We will use Keras ImageDataGenerator to create batches of images to work with. These will
include Data Augmentation steps.
# Data generator on train set with Data Augmentation
# Validation set is define here
train_datagen = ImageDataGenerator(
rescale=1./255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest',
validation_split=0.2)
#For validation and test, just rescale
test_datagen = ImageDataGenerator(rescale=1./255)
from tensorflow.keras.models import Model
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import BatchNormalization
from tensorflow.keras.layers import AveragePooling2D
from tensorflow.keras.layers import GlobalAveragePooling2D
from tensorflow.keras.layers import MaxPooling2D
from tensorflow.keras.layers import Conv2D
from tensorflow.keras.layers import Activation
from tensorflow.keras.layers import Dropout
from tensorflow.keras.layers import Flatten
from tensorflow.keras.layers import Input
from tensorflow.keras.layers import Dense
from tensorflow.keras.utils import plot_model
from tensorflow.keras import regularizers
from tensorflow.keras import backend as K
We are going to use major layers to build our CNN from scratch:
Convolution Layer: It's goal is to find features in images receinved in input
Pooling layers: Its goal is to reduce dimension while preserving main features
Correction Layer (ReLU): Replaces negative values with 0s. It is an activation layers
Dense layers: Takes a vector in input and returns another vector after applying a linear function, and eventually an activation function
Dropout: This is a regularization method, i.e. it's goal is to prevent overfitting. It does reset some proportion of weights to 0.
In the code below, we implement the CNN using a micture of VGG-16 and AlexNet as source of inspiration. Note the follwing
K.clear_session()
def custom_cnn_builder():
"""
Raison d'être: Our builder function for our homemade CNN
Args:
None
Retuns:
The Newly built model
"""
#First Convolution Layer
inputs = Input(shape=(299,299,3))
custom_CNN = Conv2D(filters=16,
kernel_size=(7,7),
padding='same',
use_bias=False)(inputs)
custom_CNN = BatchNormalization(axis=3, scale=False)(custom_CNN)
custom_CNN = Activation('relu')(custom_CNN)
custom_CNN = MaxPooling2D(pool_size=(4, 4),
strides=(4, 4),
padding='same')(custom_CNN)
custom_CNN = Dropout(0.5)(custom_CNN)
#Second Convolution Layer
custom_CNN = Conv2D(filters=32,
kernel_size=(5,5),
padding='same',
use_bias=False)(custom_CNN)
custom_CNN = BatchNormalization(axis=3, scale=False)(custom_CNN)
custom_CNN = Activation('relu')(custom_CNN)
custom_CNN = MaxPooling2D(pool_size=(4, 4),
strides=(4, 4),
padding='same')(custom_CNN)
custom_CNN = Dropout(0.5)(custom_CNN)
#Third Convolution Layer
custom_CNN = Conv2D(filters=64,
kernel_size=(3,3),
padding='same',
use_bias=False)(custom_CNN)
custom_CNN = BatchNormalization(axis=3, scale=False)(custom_CNN)
custom_CNN = Activation('relu')(custom_CNN)
custom_CNN = GlobalAveragePooling2D()(custom_CNN)
#Fully Connected layer
custom_CNN = Dense(128,activation='relu')(custom_CNN)
custom_CNN = Dense(num_breeds, activation='softmax')(custom_CNN)
my_custom_CNN = Model(inputs=inputs,
outputs=custom_CNN)
return my_custom_CNN
custom_CNN = custom_cnn_builder()
custom_CNN.summary()
# Compile the CNN Model
custom_CNN.compile(optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy", f1])
BATCH_SIZE = 16
EPOCHS = 30
history = custom_CNN.fit(
train_datagen.flow(
x_train, y_train,
batch_size=BATCH_SIZE,
subset='training'),
validation_data=train_datagen.flow(
x_train, y_train,
batch_size=BATCH_SIZE,
subset='validation'),
steps_per_epoch=int(np.ceil(x_train.shape[0] / (2*BATCH_SIZE))),
epochs=EPOCHS+20,
verbose=2)
plot_history_scores(
dict_history = history,
first_score = "accuracy",
second_score = "f1")
def hpt_cnn_model_builder(hp):
model = custom_cnn_builder()
# Tune the learning rate and beta1 for the optimizer
# Choose an optimal value from 0.01, 0.001, or 0.0001
hp_learning_rate = hp.Choice('learning_rate', values=[1e-2, 1e-3, 1e-4])
hp_beta1 = hp.Choice('beta_1', values=[0.9,0.95,0.99])
model.compile(optimizer=keras.optimizers.Adam(learning_rate=hp_learning_rate,beta_1=hp_beta1),
loss="sparse_categorical_crossentropy",
metrics=['accuracy',f1])
return model
tuner_cnn = kt.RandomSearch(hpt_cnn_model_builder,
objective='val_accuracy',
max_trials=5,
directory='my_dir_custom_cnn',
overwrite=True,
project_name='custom_cnn')
stop_early = tf.keras.callbacks.EarlyStopping(monitor='val_accuracy', patience=5)
# Search best params
tuner_cnn.search(
train_datagen.flow(
x_train, y_train,
batch_size=BATCH_SIZE,
subset='training'),
validation_data=train_datagen.flow(
x_train, y_train,
batch_size=BATCH_SIZE,
subset='validation'),
epochs=20,
callbacks=[stop_early])
# Get the optimal hyperparameters
best_hps_custom_cnn = tuner_cnn.get_best_hyperparameters(num_trials=1)[0]
print("-" * 50)
print("Custom CNN Hyperparameters optimization :")
print("-" * 50)
print(f"""
Best learning rate : {best_hps_custom_cnn.get('learning_rate')}.\n""")
print(f"""
Best beta_1 : {best_hps_custom_cnn.get('beta_1')}\n""")
hypermodel_custom_cnn = tuner_cnn.hypermodel.build(best_hps_custom_cnn)
history_custom_cnn = hypermodel_custom_cnn.fit(
train_datagen.flow(
x_train, y_train,
batch_size=BATCH_SIZE,
subset='training'),
epochs=EPOCHS+20,
validation_data=train_datagen.flow(
x_train, y_train,
batch_size=BATCH_SIZE,
subset='validation'),
verbose=2)
plot_history_scores(
dict_history = history_custom_cnn,
first_score = "accuracy",
second_score = "f1")
with plt.style.context('seaborn-whitegrid'):
plt.figure(figsize=(13,10))
plt.plot(history.history['val_accuracy'],
label='CNN')
plt.plot(history_custom_cnn.history['val_accuracy'],
label='Custom_Hypt_CNN')
plt.title('Accuracy of CUstom CNN vs Hypt Custom CNN',
fontsize=18)
plt.ylabel('Accuracy')
plt.xlabel('epoch')
plt.legend(loc='upper left')
plt.show()
from tensorflow.keras.applications.vgg16 import VGG16, preprocess_input
K.clear_session()
base_model = VGG16(weights="imagenet",
include_top=False,
input_shape=(299,299,3))
for layer in base_model.layers:
layer.trainable = False
base_model.summary()
x = Flatten()(base_model.output)
x = Dropout(0.5)(x)
x = Dense(4096, activation='relu')(x)
x = BatchNormalization()(x)
x = Dropout(0.5)(x)
x = Dense(4096, activation='relu')(x)
x = BatchNormalization()(x)
x = Dropout(0.5)(x)
predictions = Dense(num_breeds, activation = 'softmax')(x)
model = keras.Model(inputs=base_model.input, outputs=predictions)
model.summary()
model.compile(loss="sparse_categorical_crossentropy",
optimizer="adam",
metrics=["accuracy",f1])
# Data generator on train set with Data Augmentation
# Validation set is define here
train_datagen = ImageDataGenerator(
rescale=1./255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest',
validation_split=0.2,
preprocessing_function=preprocess_input)
#For validation and test, just rescale
test_datagen = ImageDataGenerator(rescale=1./255)
history_vgg16 = model.fit(
train_datagen.flow(
x_train, y_train,
batch_size=BATCH_SIZE,
subset='training'),
validation_data=train_datagen.flow(
x_train, y_train,
batch_size=BATCH_SIZE,
subset='validation'),
steps_per_epoch=int(np.ceil(x_train.shape[0] / (2*BATCH_SIZE))),
epochs=EPOCHS,
verbose=2)
plot_history_scores(
dict_history = history_vgg16,
first_score = "accuracy",
second_score = "f1")
from tensorflow.keras.applications.xception import Xception
K.clear_session()
xception_model = Xception(weights="imagenet",
include_top=False,
pooling='avg',
input_shape=(299,299,3))
for layer in xception_model.layers:
layer.trainable = False
# Add new fully-connected layers
base_xception = xception_model.output
base_xception = Dense(128, activation='relu')(base_xception)
base_xception = Dropout(0.2)(base_xception)
# Output : new classifier
predictions = Dense(num_breeds, activation='softmax')(base_xception)
# Define new model
my_xcept_model = Model(inputs=xception_model.input,
outputs=predictions)
my_xcept_model.compile(optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy", f1])
xception_model.summary()
len(xception_model.layers)
my_xcept_model.summary()
## Data generator on train set with Data Augmentation
# and preprocess_input Xception
# Validation set is define here
train_datagen = ImageDataGenerator(
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest',
validation_split=0.2,
preprocessing_function=tf.keras.applications.xception.preprocess_input)
#For validation and test, just rescale
test_datagen = ImageDataGenerator(
preprocessing_function=tf.keras.applications.xception.preprocess_input)
history_xcept = my_xcept_model.fit(
train_datagen.flow(
x_train, y_train,
batch_size=BATCH_SIZE,
subset='training'),
validation_data=train_datagen.flow(
x_train, y_train,
batch_size=BATCH_SIZE,
subset='validation'),
steps_per_epoch=int(np.ceil(x_train.shape[0] / (2*BATCH_SIZE))),
epochs=EPOCHS,
verbose=2)
plot_history_scores(
dict_history = history_xcept,
first_score = "accuracy",
second_score = "f1")
from tensorflow.keras.applications import ResNet50
K.clear_session()
resnet_model = ResNet50(
weights='imagenet',
include_top=False,
pooling='avg',
input_shape=(299,299,3))
# Dont retrain layers
for rn_layer in resnet_model.layers:
rn_layer.trainable = False
# Add new fully-connected layers
rn_base_output = resnet_model.output
rn_base_output = Dense(128, activation='relu')(rn_base_output)
rn_base_output = Dropout(0.5)(rn_base_output)
# Output : new classifier
rn_predictions = Dense(num_breeds, activation='softmax')(rn_base_output)
# Define new model
my_resnet_model = Model(inputs=resnet_model.input,
outputs=rn_predictions)
my_resnet_model.compile(optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy", f1])
# Data generator on train set with Data Augmentation
# and preprocess_input Resnet
# Validation set is define here
rn_train_datagen = ImageDataGenerator(
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest',
validation_split=0.2,
preprocessing_function=tf.keras.applications.resnet.preprocess_input)
#For validation and test, just rescale
rn_test_datagen = ImageDataGenerator(
preprocessing_function=tf.keras.applications.resnet.preprocess_input)
history_resnet = my_resnet_model.fit(
rn_train_datagen.flow(
x_train, y_train,
batch_size=BATCH_SIZE,
subset='training'),
validation_data=rn_train_datagen.flow(
x_train, y_train,
batch_size=BATCH_SIZE,
subset='validation'),
steps_per_epoch=int(np.ceil(x_train.shape[0] / (2*BATCH_SIZE))),
epochs=EPOCHS,
verbose=2)
plot_history_scores(
dict_history = history_resnet,
first_score = "accuracy",
second_score = "f1")
with plt.style.context('seaborn-whitegrid'):
plt.figure(figsize=(13,10))
plt.plot(history.history['val_accuracy'],
label='Custom CNN')
plt.plot(history_custom_cnn.history['val_accuracy'],
label='Hypt custom CNN - Mean accuracy: {:.2f}'.format(
np.mean(history_custom_cnn.history['val_accuracy'])))
plt.plot(history_xcept.history['val_accuracy'],
label='Xception - Mean accuracy: {:.2f}'.format(
np.mean(history_xcept.history['val_accuracy'])))
plt.plot(history_resnet.history['val_accuracy'],
label='Resnet50 - Mean accuracy: {:.2f}'.format(
np.mean(history_resnet.history['val_accuracy'])))
plt.plot(history_vgg16.history['val_accuracy'],
label='VGG-16 - Mean accuracy: {:.2f}'.format(
np.mean(history_vgg16.history['val_accuracy'])))
plt.title('Accuracy of differents ConvNet tested over epochs',
fontsize=18)
plt.ylabel('Accuracy')
plt.xlabel('epoch')
plt.legend(loc='upper left')
plt.show()
We decided to keep the Xception model for the rest of this project as it gives the best performance on our chosen metrics
We will use kerastuner to fine tune the connected layer we added to Xception
def model_builder(hp):
# Load base model
xception_model = tf.keras.applications.xception.Xception(
weights='imagenet',
include_top=False,
pooling='avg',
input_shape=(299,299,3))
for layer in xception_model.layers:
layer.trainable = False
base_output = xception_model.output
# Tune dense units
hp_units = hp.Int('dense_units',
min_value=32,
max_value=300,
step=32,
default=128)
base_output = Dense(units=hp_units,
activation='relu')(base_output)
base_output = Dropout(0.5)(base_output)
# Output : new classifier
predictions = Dense(num_breeds, activation='softmax')(base_output)
# Define new model
my_xcept_model = Model(inputs=xception_model.input,
outputs=predictions)
# Tune learning rate
hp_learning_rate = hp.Choice(
name='learning_rate',
values=[1e-2, 1e-3, 1e-4])
hp_beta1 = hp.Choice(
name='beta_1',
values=[0.9,0.95,0.99])
my_xcept_model.compile(
optimizer=keras.optimizers.Adam(learning_rate=hp_learning_rate, beta_1=hp_beta1),
loss="sparse_categorical_crossentropy",
metrics=["accuracy", f1])
return my_xcept_model
# Tune the learning rate for the optimizer
# Constuct the tuner of kerastuner
tuner = kt.RandomSearch(
model_builder,
objective='val_accuracy',
max_trials=5,
directory='my_dir',
overwrite=True,
project_name='Xcept_kt'
)
# Define a early stopping
stop_early = tf.keras.callbacks.EarlyStopping(
monitor='val_accuracy',
patience=5)
# Search best params
tuner.search(
train_datagen.flow(
x_train, y_train,
batch_size=BATCH_SIZE,
subset='training'),
validation_data=train_datagen.flow(
x_train, y_train,
batch_size=BATCH_SIZE,
subset='validation'),
epochs=20,
callbacks=[stop_early])
# Get the optimal hyperparameters
best_hps = tuner.get_best_hyperparameters(num_trials=1)[0]
print("-" * 50)
print("Xception Hyperparameters optimization :")
print("-" * 50)
print(f"""
Best learning rate : {best_hps.get('learning_rate')}.\n
Best Dense units : {best_hps.get('dense_units')}.\n
Best beta_1 : {best_hps.get('beta_1')}.
""")
Now that we have the optimal parameters, we can now retrain the model to have the fully connected layer optimised
hypermodel = tuner.hypermodel.build(best_hps)
hypermodel.fit(
train_datagen.flow(
x_train, y_train,
batch_size=BATCH_SIZE,
subset='training'),
epochs=EPOCHS,
validation_data=train_datagen.flow(
x_train, y_train,
batch_size=BATCH_SIZE,
subset='validation'),
verbose=2)
hypermodel.save('xception_hypermodel.h5')
print("Model saved")
Remember at this point we only optimised the layers "outside" of Xception. Hence now we would like to re-train only some parts of the blocks of Xception
Xception has 3 flows:
We are only going to retrain the exit flow with the previous newly optimised fully connected layer parameters. That is the reason why we only unfrezze the layers after the 115th layer
def xception_fine_tune(nb_layers):
"""
Raison d'être: Training some parts only of model and returning the trained model
Args:
nb_layer: number of layers NOT to be trained
Returns:
hypermodel_t: the newly trained model
"""
# Load the pre trained model
hypermodel_t = load_model('./xception_hypermodel.h5', custom_objects={"f1": f1})
# re train the last layers
for i, layer in enumerate(hypermodel_t.layers):
if i < nb_layers:
layer.trainable = False
else:
layer.trainable = True
# Compile model
hypermodel_t.compile(
optimizer='adam',
loss="sparse_categorical_crossentropy",
metrics=["accuracy", f1])
return hypermodel_t
# Define a early stopping
stop_early = tf.keras.callbacks.EarlyStopping(
monitor='val_accuracy',
patience=5)
# Dont train the 115 first layers. Last layer excluding the exit flow is layer 115. Then we get in the exit flow.
my_tuned_xcept_model = xception_fine_tune(115)
fine_tuned_history = my_tuned_xcept_model.fit(
train_datagen.flow(
x_train, y_train,
batch_size=BATCH_SIZE,
shuffle=False,
subset='training'),
epochs=EPOCHS,
validation_data=train_datagen.flow(
x_train, y_train,
batch_size=BATCH_SIZE,
shuffle=False,
subset='validation'),
callbacks=[stop_early],
verbose=2)
my_tuned_xcept_model.save('my_tuned_xcept_model.h5')
print("Tuned Model saved")
plot_history_scores(
dict_history = fine_tuned_history,
first_score = "accuracy",
second_score = "f1")
with plt.style.context('seaborn-whitegrid'):
plt.figure(figsize=(13,10))
plt.plot(history.history['val_accuracy'],
label='CNN - Mean accuracy: {:.2f}'.format(
np.mean(history.history['val_accuracy'])))
plt.plot(history_custom_cnn.history['val_accuracy'],
label='Hypt custom CNN - Mean accuracy: {:.2f}'.format(
np.mean(history_custom_cnn.history['val_accuracy'])))
plt.plot(history_xcept.history['val_accuracy'],
label='Xception - Mean accuracy: {:.2f}'.format(
np.mean(history_xcept.history['val_accuracy'])))
plt.plot(history_resnet.history['val_accuracy'],
label='Resnet50 - Mean accuracy: {:.2f}'.format(
np.mean(history_resnet.history['val_accuracy'])))
plt.plot(history_vgg16.history['val_accuracy'],
label='VGG-16 - Mean accuracy: {:.2f}'.format(
np.mean(history_vgg16.history['val_accuracy'])))
plt.plot(fine_tuned_history.history['val_accuracy'],
label='Fine-tuned Xception - Mean accuracy: {:.2f}'.format(
np.mean(fine_tuned_history.history['val_accuracy'])))
plt.title('Accuracy of differents ConvNet tested over epochs',
fontsize=18)
plt.ylabel('Validation accuracy')
plt.xlabel('epoch')
plt.legend(loc='upper left')
plt.show()
# Model evaluation on test set
xception_eval = fine_tuned_history.model.evaluate(
test_datagen.flow(
x_test, y_test,
batch_size=BATCH_SIZE,
shuffle=False),
verbose=1)
print("-" * 50)
print("Xception model evaluation :")
print("-" * 50)
print('Test Loss: {:.3f}'.format(xception_eval[0]))
print('Test Accuracy: {:.3f}'.format(xception_eval[1]))
print('Test F1 score: {:.3f}'.format(xception_eval[2]))
# Make predictions
Y_pred = fine_tuned_history.model.predict(
test_datagen.flow(
x_test, y_test,
batch_size=BATCH_SIZE,
shuffle=False))
y_pred = np.argmax(Y_pred, axis=1)
# Inverse transform of encoding
y_pred_s = encoder.inverse_transform(y_pred)
y_test_s = encoder.inverse_transform(y_test)
# Confusion Matrix
cf_matrix = confusion_matrix(y_test, y_pred)
fig = plt.figure(figsize=(12,10))
ax = sns.heatmap(cf_matrix, annot=True)
ax.set_xlabel("PREDICTED LABELS", color="g")
ax.set_ylabel("TRUE LABELS", color="orange")
ax.xaxis.set_ticklabels(encoder.classes_,
rotation='vertical')
ax.yaxis.set_ticklabels(encoder.classes_,
rotation='horizontal')
plt.title("Confusion Matrix on Xception predicted results\n",
fontsize=18)
plt.show()
# Classification report
print(classification_report(
y_test, y_pred,
target_names=sorted(set(y_test_s))))
fig = plt.figure(1, figsize=(20,20))
fig.patch.set_facecolor('#343434')
plt.suptitle("Predicted VS actual for Xception model fine-tuned",
y=.92, fontsize=22,
color="white")
n = 0
for i in range(12):
n+=1
r = int(np.random.randint(0, x_test.shape[0], 1))
plt.subplot(3,4,n)
plt.subplots_adjust(hspace = 0.1, wspace = 0.1)
plt.imshow(image.array_to_img(x_test[r]))
plt.title('Actual = {}\nPredicted = {}'.format(y_test_s[r] , y_pred_s[r]),
color="white")
plt.xticks([]) , plt.yticks([])
plt.show()